﻿using Dyao.Book.Application.Abstractions;
using Dyao.Book.BusApplication;
using Dyao.Book.Contract;
using Dyao.Book.Core;
using Dyao.Book.Entity;
using Dyao.Repository.Abstractions;
using Dyao.Repository.Abstractionsx;
using Foundation.Core;
using Foundation.DistributeLock;
using Foundation.Uow;
using Microsoft.Extensions.DependencyInjection;

namespace Dyao.Book.Application
{
    public class TaskCenterApplication : BaseApplication, ITaskCenterApplication
    {
        private readonly ITaskCenterSettingsRepository _taskCenterSettingsRepository;
        private readonly ITaskCenterRuleRepository _taskCenterRuleRepository;
        private readonly ITaskCenterRecordRepository _taskCenterRecordRepository;
        private readonly ITaskCenterRecordLogRepository _taskCenterRecordLogRepository;
        private readonly ITaskCenterRecordExtensionRepository _taskCenterRecordExtensionRepository;
        private readonly IDistributeLocker _distributeLocker;

        public TaskCenterApplication(ITaskCenterSettingsRepository taskCenterSettingsRepository
            , ITaskCenterRuleRepository taskCenterRuleRepository
            , ITaskCenterRecordRepository taskCenterRecordRepository
            , ITaskCenterRecordLogRepository taskCenterRecordLogRepository
            , ITaskCenterRecordExtensionRepository taskCenterRecordExtensionRepository
            , IDistributeLocker distributeLocker)
        {
            _taskCenterSettingsRepository = taskCenterSettingsRepository;
            _taskCenterRuleRepository = taskCenterRuleRepository;
            _taskCenterRecordRepository = taskCenterRecordRepository;
            _taskCenterRecordLogRepository = taskCenterRecordLogRepository;
            this._taskCenterRecordExtensionRepository = taskCenterRecordExtensionRepository;
            _distributeLocker = distributeLocker;
        }

        /// <summary>
        /// 创建任务
        /// </summary>
        /// <param name="taskCenterCreateModel">任务查询参数</param>
        /// <param name="cancellationToken">cancellationToken</param>
        /// <returns></returns>
        public async Task<int> CreateTaskAsync(TaskCenterCreateDto taskCenterCreateModel, object requestParams, CancellationToken cancellationToken = default)
        {
            if (taskCenterCreateModel is null)
            {
                throw new ArgumentNullException(nameof(taskCenterCreateModel));
            }

            if (string.IsNullOrWhiteSpace(taskCenterCreateModel.TaskCode))
            {
                throw new ArgumentNullException(nameof(taskCenterCreateModel.TaskCode));
            }

            if (!TaskCenterCodeManager.IsExists(taskCenterCreateModel.TaskCode))
            {
                throw new BusinessException(CommonExceptionCode.TaskCenterRecordNotFound, $"{nameof(taskCenterCreateModel.TaskCode)}[{taskCenterCreateModel.TaskCode}]不存在");
            }

            //1、验证权限 2、查询任务配置 3、查询对应规则 4、找到对应规则代码实例 5、创建任务 6、创建历史记录
            TaskCenterSettingsDto taskCenterSettingsModel = await GetTaskCenterSettingAsync(taskCenterCreateModel.TaskCode, cancellationToken);
            if (taskCenterSettingsModel == null)
            {
                throw new BusinessException(CommonExceptionCode.TaskCenterCreateRecordTaskSettingNotFound, $"任务配置[{taskCenterCreateModel.TaskCode}]不存在");
            }

            // 校验权限

            var idList = !string.IsNullOrWhiteSpace(taskCenterSettingsModel.RuleIds) ? taskCenterSettingsModel.RuleIds.SplitDefaultToIntList() : null;
            var ruleExcutor = ServiceProvider.GetService<CompositeTaskRuleExcutor>();

            var excuteModel = new CompositeTaskCenterRuleExcutingContext()
            {
                Parameters = requestParams,
                TaskCode = taskCenterCreateModel.TaskCode,
                Category = taskCenterSettingsModel.Category,
                RuleIds = idList
            };

            await ruleExcutor.ExcuteAsync(excuteModel);

            var reqestStr = await GetService<ITaskCenterParametersSerializerFactory>()
                .Create(new TaskCenterDto { TaskCode = taskCenterCreateModel.TaskCode, Category = taskCenterSettingsModel.Category.ToString() })
                .SerializeAsync(taskCenterCreateModel.TaskCode, taskCenterSettingsModel.Category, requestParams, cancellationToken);

            return await CreateTaskCenterRecordAsync(taskCenterSettingsModel, taskCenterCreateModel, reqestStr, cancellationToken);
        }

        /// <summary>
        /// 创建任务记录
        /// </summary>
        /// <param name="taskCenterSettingsModel">任务配置信息</param>
        /// <param name="taskCenterFilterModel">任务查询参数</param>
        /// <param name="cancellationToken">cancellationToken</param>
        /// <returns></returns>
        private async Task<int> CreateTaskCenterRecordAsync(TaskCenterSettingsDto taskCenterSettingsModel, TaskCenterCreateDto taskCenterFilterModel, string requestParams, CancellationToken cancellationToken = default)
        {
            ITypeFinder typeFinder = ServiceProvider.GetService<ITypeFinder>();
            Type type = typeFinder.GetByFullName(taskCenterSettingsModel.CommandName);

            if (type is null)
            {
                throw new BusinessException("TaskCenter_CreateTask_CommandNotfound", $"任务Code[{taskCenterFilterModel.TaskCode}]命令找不到！");
            }

            var command = (ITaskCenterCommand)Activator.CreateInstance(type);

            if (command is null)
            {
                throw new BusinessException("TaskCenter_CreateTask_CommandUnableInstance", $"任务Code[{taskCenterFilterModel.TaskCode}]命令无法实例化");
            }

            TaskCenterRecordAddDto taskCenterRecordModel = new TaskCenterRecordAddDto
            {
                TaskCenterSettingsId = taskCenterFilterModel.TaskCode.ToString(),
                Category = taskCenterSettingsModel.Category,
                MenuPath = taskCenterFilterModel.MenuPath,
                RetryCountMax = taskCenterSettingsModel.MaxRetryCount,
                ExcutingProgress = 0,
                RetryCount = 0,
                TimeOutSecond = taskCenterSettingsModel.TimeOutSecond,
                IsTimeOut = false,
                Status = TaskCenterRecordStatusEnum.Pending,
                CreateUserId = CurrentUser.GetUserId().ToInt(),
                CreateUserName = CurrentUser.UserName,
                CreateDateTime = DateTime.Now,
                UpdateUserId = CurrentUser.GetUserId().ToInt(),
                UpdateUserName = CurrentUser.UserName,
                UpdateDateTime = DateTime.Now,
                IsDel = false
            };

            var taskCenterRecordExtension = new TaskCenterRecordExtensionAddDto
            {
                Params = requestParams
            };

            taskCenterRecordModel.TaskCenterRecordExtensionAddDto = taskCenterRecordExtension;
            var taskCenterRecordId = await PostTaskCenterRecordAsync(taskCenterRecordModel, cancellationToken);

            var taskCenterRecordLogModel = new TaskCenterRecordLogDto
            {
                TaskCenterRecordId = taskCenterRecordId,
                Message = "任务创建成功",
                Type = TaskCenterRecordLogTypeEnum.Business,
                CreateUserName = CurrentUser.UserName,
                CreateDateTime = DateTime.Now
            };
            await PostTaskCenterRecordLogAsync(taskCenterRecordLogModel, cancellationToken);

            command.TaskCenterDto = new TaskCenterDto
            {
                TaskCenterRecordId = taskCenterRecordId,
                CurrentRetryCount = 0,
                Category = taskCenterSettingsModel.Category.ToString(),
                TaskCode = taskCenterFilterModel.TaskCode,
            };

            ServiceBus.SendOneWayCommand(command);

            return taskCenterRecordId;
        }

        /// <summary>
        /// 创建任务记录
        /// </summary>
        /// <param name="taskCenterRecordModel">taskCenterRecordModel</param>
        /// <param name="cancellationToken">cancellationToken</param>
        /// <returns></returns>
        private async Task<int> PostTaskCenterRecordAsync(TaskCenterRecordAddDto taskCenterRecordModel, CancellationToken cancellationToken = default)
        {
            using (var unitOfWork = UnitOfWorkManager.Begin(true, true))
            {
                TaskCenterRecordEntity taskCenterRecord = ObjectMapper.Map<TaskCenterRecordAddDto, TaskCenterRecordEntity>(taskCenterRecordModel);
                taskCenterRecord = await _taskCenterRecordRepository.InsertAsync(taskCenterRecord, false, cancellationToken);
                await unitOfWork.SaveChangesAsync(cancellationToken);

                var taskCenterRecordExtension = ObjectMapper.Map<TaskCenterRecordExtensionAddDto, TaskCenterRecordExtensionEntity>(taskCenterRecordModel.TaskCenterRecordExtensionAddDto);
                taskCenterRecordExtension.ID = taskCenterRecord.ID;
                await _taskCenterRecordExtensionRepository.InsertAsync(taskCenterRecordExtension, false, cancellationToken);
                await unitOfWork.CompleteAsync(cancellationToken);

                return taskCenterRecord.ID;
            }
        }

        /// <summary>
        /// 获取任务中心规则列表
        /// </summary>
        /// <param name="taskRuleId">taskRuleId</param>
        /// <param name="cancellationToken">cancellationToken</param>
        /// <returns></returns>
        private async Task<TaskCenterRuleDto> GetTaskCenterRuleAsync(int taskRuleId, CancellationToken cancellationToken = default)
        {
            using (var unitOfWork = UnitOfWorkManager.Begin())
            {
                var taskCenterRule = await _taskCenterRuleRepository.GetAsync(taskRuleId, cancellationToken);

                TaskCenterRuleDto taskCenterRuleModel = new TaskCenterRuleDto
                {
                    Id = taskCenterRule.ID,
                    Name = taskCenterRule.Name,
                    RuleSettings = taskCenterRule.RuleSettings
                };
                return taskCenterRuleModel;
            }
        }

        /// <summary>
        /// 获取任务配置
        /// </summary>
        /// <param name="taskCenterSettingId">taskCenterSettingId</param>
        /// <param name="cancellationToken">cancellationToken</param>
        /// <returns></returns>
        private async Task<TaskCenterSettingsDto> GetTaskCenterSettingAsync(string taskCenterSettingId, CancellationToken cancellationToken = default)
        {
            using (var unitOfWork = UnitOfWorkManager.Begin())
            {
                var taskCenterSetting = await _taskCenterSettingsRepository.FindAsync(taskCenterSettingId, cancellationToken);
                if (taskCenterSetting == null) return null;

                var taskCenterSettingsModel = ObjectMapper.Map<TaskCenterSettingsEntity, TaskCenterSettingsDto>(taskCenterSetting);
                return taskCenterSettingsModel;
            }
        }

        /// <summary>
        /// 添加记录日志
        /// </summary>
        /// <param name="recordLogModel">recordLogModel</param>
        /// <param name="cancellationToken">cancellationToken</param>
        /// <returns></returns>
        private async Task<bool> PostTaskCenterRecordLogAsync(TaskCenterRecordLogDto recordLogModel, CancellationToken cancellationToken = default)
        {
            using (var unitOfWork = UnitOfWorkManager.Begin())
            {
                var taskCenterRecordLog = ObjectMapper.Map<TaskCenterRecordLogDto, TaskCenterRecordLogEntity>(recordLogModel);
                taskCenterRecordLog = await _taskCenterRecordLogRepository.InsertAsync(taskCenterRecordLog, false, cancellationToken);
                await unitOfWork.SaveChangesAsync(cancellationToken);
                return true;
            }
        }
    }
}
